﻿// <copyright file="AppNotification.cs" company="Robert Venables">
// Copyright (c) 2009 Robert Venables.
// </copyright>
// <author>Robert Venables</author>
// <email>rob@rvenables.com</email>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace VNotify
{
    /// <summary>
    /// Represents an individual notification.
    /// </summary>
    [System.Serializable]
    public class AppNotification : System.IEquatable<AppNotification>
    {
        #region "Constructors"

            /// <summary>
            /// Initializes a new instance of the AppNotification class.
            /// </summary>
            public AppNotification() 
            {
            }

            /// <summary>
            /// Initializes a new instance of the AppNotification class
            /// with the specified message.
            /// </summary>
            /// <param name="message">The initial notification message text.</param>
            public AppNotification(string message)
            {
                if (string.IsNullOrEmpty(message))
                    throw new ArgumentException("Message is invalid.");

                this.Message = message;
            }
        #endregion

        #region "Notification Properties"

            /// <summary>
            /// Gets or sets the main message text. Visible in the initial notification popup.
            /// </summary>
            public string Message { get; set; }

            /// <summary>
            /// Gets or sets the title of notification. Visible in message details 
            /// (but not in initial notification popup).
            /// </summary>
            public string Title { get; set; }

            /// <summary>
            /// Gets or sets the long message visible in message details. HTML Allowed.
            /// </summary>
            public string LongMessage { get; set; }

            /// <summary>
            /// Gets or sets the long message preview visible in the initial notification popup.
            /// </summary>
            public string LongMessagePreview { get; set; }

            /// <summary>
            /// Gets or sets the message priority.
            /// </summary>
            public int MessageLevel { get; set; }

            /// <summary>
            /// Gets or sets a value indicating whether the 
            /// audible alert for current message should be suppressed.
            /// </summary>
            public bool Silent { get; set; }

            /// <summary>
            /// Gets or sets the specific sound that will be played at the recipient.
            /// Note: will not play when Silent is set to True.
            /// </summary>
            public AppNotificationSound Sound { get; set; }

            /// <summary>
            /// Gets or sets the URL to open when the custom button is pressed.
            /// </summary>
            public string RunCommand { get; set; }

            /// <summary>
            /// Gets or sets the button text for the custom button. Preferably under 12 characters.
            /// </summary>
            public string NotificationButtonText { get; set; }

        #endregion

        // AppNotification objects can be queried for value equality.
        #region "Value Equality Glue"

            /// <summary>
            /// Equality operator overriden for value comparison.
            /// </summary>
            /// <param name="current">The first (AppNotification) object to compare.</param>
            /// <param name="other">The second object to compare.</param>
            /// <returns>The result of the equality check.</returns>
            public static bool operator ==(AppNotification current, object other)
            {
                if ((object)current == null && (object)other == null) return true;

                AppNotification otherNotification = other as AppNotification;

                /* Warning: Do not remove object cast - will cause this operator
                 * to be called recursively and a StackOverflowException to occur.
                 */ 
                
                if ((object)otherNotification == null) return false;

                if (System.Object.ReferenceEquals(current, otherNotification)) return true;

                return NotificationEquals(current, otherNotification);
            }

            /// <summary>
            /// Inequality operator overriden for value comparison.
            /// </summary>
            /// <param name="current">The first (AppNotification) object to compare.</param>
            /// <param name="other">The second object to compare.</param>
            /// <returns>The result of the inequality check.</returns>
            public static bool operator !=(AppNotification current, object other)
            {
                return !(current == other);
            }

            /// <summary>
            /// A hash code implementation that works consistently with the Equals
            /// implementation and [in]equality operators. 
            /// </summary>
            /// <returns>
            /// A unique hash code that corresponds to
            /// the value of the notification.
            /// </returns>
            public override int GetHashCode()
            {
                 return this.Sound.GetHashCode() ^
                        (this.RunCommand ?? string.Empty).GetHashCode() ^
                        (this.NotificationButtonText ?? string.Empty).GetHashCode() ^
                        this.Silent.GetHashCode() ^
                        this.MessageLevel.GetHashCode() ^
                        (this.LongMessagePreview ?? string.Empty).GetHashCode() ^
                        (this.Title ?? string.Empty).GetHashCode() ^
                        (this.LongMessage ?? string.Empty).GetHashCode() ^
                        (this.Message ?? string.Empty).GetHashCode();
            }

            /// <summary>
            /// Compares the values of this object against (object) other.
            /// </summary>
            /// <param name="obj">The object of which to compare values against.</param>
            /// <returns>True if both objects have the same value.</returns>
            public override bool Equals(object obj)
            {
                AppNotification otherNotification = obj as AppNotification;

                if (otherNotification == null) return false;

                return NotificationEquals(this, otherNotification);
            }

            #region IEquatable<AppNotification> Members

                /// <summary>
                /// Compares the current AppNotification object to the supplied
                /// obj AppNotification.
                /// </summary>
                /// <param name="obj">The AppNotification to compare against.</param>
                /// <returns>The result of the comparison.</returns>
                bool System.IEquatable<AppNotification>.Equals(AppNotification obj)
                {
                    if (System.Object.ReferenceEquals(this, obj)) return true;

                    return NotificationEquals(this, obj);
                }

            #endregion

        #endregion

        /// <summary>
        /// Returns a deep copy of the object.
        /// </summary>
        /// <returns>New (copied) AppNotification object.</returns>
        public AppNotification DeepCopy()
        {
            return new AppNotification()
            {
                Message = this.Message,
                LongMessage = this.LongMessage,
                LongMessagePreview = this.LongMessagePreview,
                MessageLevel = this.MessageLevel,
                NotificationButtonText = this.NotificationButtonText,
                RunCommand = this.RunCommand,
                Silent = this.Silent,
                Sound = this.Sound,
                Title = this.Title
            };
        }

        /// <summary>
        /// Compares two AppNotification objects.
        /// </summary>
        /// <param name="first">The first AppNotification object to compare.</param>
        /// <param name="second">The second AppNotification object to compare.</param>
        /// <returns>The result of the comparison by value.</returns>
        private static bool NotificationEquals(AppNotification first, AppNotification second)
        {
            if (first.Sound != second.Sound) return false;
            if (first.RunCommand != second.RunCommand) return false;
            if (first.NotificationButtonText != second.NotificationButtonText) return false;
            if (first.Silent != second.Silent) return false;
            if (first.MessageLevel != second.MessageLevel) return false;
            if (first.LongMessagePreview != second.LongMessagePreview) return false;
            if (first.Title != second.Title) return false;
            if (first.LongMessage != second.LongMessage) return false;
            if (first.Message.Equals(second.Message) == false) return false;

            return true;
        }
    }
}